home *** CD-ROM | disk | FTP | other *** search
- /*
- * SetQuicText: Hypercard XCMD to set up a text QuicKey with a text string of up to 72 characters.
- * Usage: SetQuicText modifiers, virtual key, text
- * Modifiers can be one or more of "C" (Command), "L" (CapsLock), "O" (Option),
- * "c" (Control), and "S" (Shift).
- * The virtual key is a hardware-independent method of identifying a key. There's a
- * table of key/char equivalences in Inside Macintosh Volume V, and also in the stack
- * distributed with the PostEvent XCMD.
- * Note that the text key has to be defined before this XCMD is run - i.e. the slot has
- * to be reserved, and is assumed to be universal rather than program-specific (the
- * XCMD looks at both, but checks universal first).
- * Dewi Williams. Delphi: Dewi.
- */
-
- #include <MemoryMgr.h>
- #include <EventMgr.h>
- #include <HyperXCmd.h> /* Defines and structures for HyperCard XCMD programming */
- #include <Environs.h> /* Defines for the SysEnvirons trap */
- #include <ScriptMgr.h> /* Came with the 2.11 upgrade as "xScriptMgr.h" */
- #include "QuicKeys.h" /* Defines and structures for QuicKeys internals access */
-
- #define NULL 0L
- #define HiWord(x) (((unsigned short *)&(x))[0])
- #define LoWord(x) (((unsigned short *)&(x))[1])
- #define controlKey 4096
-
- /* Forward references */
- QuicInitBlock *FindSysHeap();
- int CalcModifiers(StringPtr str);
- int CalculateCharCode(int modifiers, int theKey);
- Boolean UpdateKeySlot(QuicInitBlock *qb, int kcode, int modifiers, StringPtr text);
-
- pascal void
- main(paramPtr)
- XCmdBlockPtr paramPtr;
- {
- Str255 text;
- QuicInitBlock *qb;
- int theKey;
- int modifiers;
- SysEnvRec env;
- int kcode;
-
- /* Ensure that this is system 4.1 or later. This is needed for KeyTrans and extended keyboard
- * checks. It ensures that KCHR/KMAP keyboard mappings are in place.
- */
- if (SysEnvirons(1, &env) == envNotPresent) {
- /* We beep rather than put up an error message because I don't like hardwiring English
- * strings into programs, and haven't figured out an owned resource type of technique for
- * putting the error messages into resources. Apple needs to set a standard here (minor editorial!).
- */
- SysBeep(1);
- return;
- }
-
- /* There should be 3 parameters. */
- if (paramPtr->paramCount != 3) {
- SysBeep(1);
- return;
- }
-
- /* Find QuicKeys in the system heap. */
- if ( (qb = FindSysHeap()) == NULL) {
- /* Not running QuicKeys */
- SysBeep(1);
- return;
- }
-
- /* First param is the modifiers. Convert it to a pascal string */
- ZeroToPas(paramPtr,*(paramPtr->params[0]), text);
-
- modifiers = CalcModifiers(text);
-
- /* If the control key is specified, see if this is possible with the current keyboard. */
- if (modifiers&controlKey) {
- /* Make no assumptions about new keyboard models! */
- if (env.keyBoardType <= envStandADBKbd && env.keyBoardType != envAExtendKbd) {
- SysBeep(1);
- return;
- }
- }
-
- /* The second param is the virtual keycode. */
- ZeroToPas(paramPtr,*(paramPtr->params[1]), text);
- theKey = ((int)StrToNum(paramPtr, (Str31 *)text)) & 0x7F;
-
- /* Sanity check: virtual keycodes past 0x60 belong to the extended keyboard (function keys, PageUp
- * etc. To stop any possible confusion, we check for the existence of the extended keyboard before
- * posting any such event.
- */
- if (theKey > 0x60 && env.keyBoardType != envAExtendKbd) {
- SysBeep(1);
- return;
- }
-
- /* Third parameter is the text to substitute. */
- ZeroToPas(paramPtr,*(paramPtr->params[2]), text);
-
- /* Clamp the string if it's too big. */
- if (text[0] > 71) text[0] = 71; /* with room for the length byte */
-
- if ( (kcode = CalculateCharCode(modifiers, theKey)) == 0) {
- /* Bad virtual keycode? */
- SysBeep(1);
- return;
- }
-
- if (UpdateKeySlot(qb, kcode, modifiers, text) == FALSE) {
- /* Slot wasn't reserved in universal key area. */
- SysBeep(1);
- }
- }
-
- /*
- * This is a C version of the example code in Chapter 8 of the QuicKeys manual.
- */
-
- QuicInitBlock *
- FindSysHeap()
- {
- register Ptr endBlk = SysZone->bkLim;
- register QuicInitBlock *qp;
-
- qp = (QuicInitBlock *) &SysZone->heapData;
-
- while(qp != (QuicInitBlock *) endBlk) {
- /* Analyze the block we're looking at. */
- if ((qp->header[0] & 0xC0) == 0x40) { /* Is it non-relocatable? */
- /* Check magic and signature. */
- if (qp->quic.magic == 0xa89f1234 && qp->quic.signature == 'CELN') {
- /* Chapter 8 states that the version number is 1. It's actually 0 (as the example
- * assembly language shows and a quick call to CE Software confirmed).
- */
- if (qp->quic.version == 0) return qp;
- }
- }
-
- /* Time to move on to the next block. The 0xFFFFFF strips off the tag byte(s). */
- qp = (QuicInitBlock *)(((Byte *)qp) + ((* (long *)&qp->header) & 0xFFFFFF));
- }
- return NULL; /* Failed to find it */
- }
-
- /*
- * CalculateCharCode: given a virtual keycode value, calculate the keycode/charcode combination.
- */
-
- int
- CalculateCharCode(modifiers, theKey)
- int modifiers;
- int theKey;
- {
- long kResult;
- long state = 0;
- Handle hKeyData;
- register int kchrID;
- int theCode;
-
- /* Calculate the resource ID of the relevant KCHR resource. The Script Manager has
- * this information. This may be useful if you're using Dvorak mappings, for instance.
- * I haven't really been able to test this - 0 is the US default, and it's the only one I
- * have.
- */
- kchrID = (int)GetScript(GetEnvirons(smKeyScript), smScriptKeys);
-
- if ( (hKeyData = GetResource('KCHR', kchrID)) == NULL) {
- /* We've confirmed that it is System 4.1 or later. Strange. */
- SysBeep(1);
- return;
- }
-
- /* The keyCode parameter passed to the KeyTrans trap consists of the modifier
- * flags in bits 8-15, up/down stroke in bit 7 (1 = up), and the virtual key
- * code in bits 6 - 0.
- */
- modifiers |= btnState; /* The mouse button is UP */
- theKey |= modifiers; /* Already in bits 8-15 */
-
- /* I'm assuming here that KeyTrans doesn't move the heap. Don't see why it should. */
- if ( (kResult = KeyTrans(*hKeyData, theKey, &state)) == 0) return 0;
-
- /* kResult consists of 2 16 bit characters to be posted as events (usually the high word of each is 0),
- * high word first. A return value of 0 in either word should not be posted.
- */
- if ((theCode = HiWord(kResult)) != 0) {
- if (LoWord(kResult) != 0) {
- /* This combination's inappropriate - it has to be a single keycode/charcode combination. */
- return 0;
- }
- } else {
- theCode = LoWord(kResult);
- }
-
- theKey &= 0x7F; /* Cut out any modifiers */
- theKey <<= 8; /* And shift to the keyCode position */
- theCode |= theKey;
-
- return theCode;
- }
-
- /* Convert the modifier string to its numeric equivalent. This code isn't perfect - it does
- * blind matches without validating for odd characters. For instance "LXO" == "LO".
- */
-
- static int
- CalcModifiers(str)
- register StringPtr str;
- {
- register StringPtr end = str + str[0] + 1;
- register int modifiers = 0;
-
- for (str++;str < end; str++) {
- switch( (*str) ) {
- case 'C':
- modifiers |= cmdKey;
- break;
- case 'S':
- modifiers |= shiftKey;
- break;
- case 'L':
- modifiers |= alphaLock;
- break;
- case 'O':
- modifiers |= optionKey;
- break;
- case 'c':
- modifiers |= controlKey;
- break;
- }
- }
- return modifiers;
- }
-
- /*
- * Write "theText" into the QuicKeys text key slot identified by "kcode". Look in universal first, then
- * in program-specific.
- */
-
- Boolean
- UpdateKeySlot(qb, kcode, modifiers, theText)
- QuicInitBlock *qb;
- int kcode;
- int modifiers;
- StringPtr theText;
- {
- register KeyRecord *kr = qb->quic.universal;
- register KeyRecord *end = kr + N_QCKEYS;
-
- for (; kr < end; kr++) {
- if (kr->QKtype == QK_TEXT) {
- if ((kr->key) == kcode && (kr->modifiers == modifiers)) {
- BlockMove(theText, kr->u.QuicText.text, (Size)(theText[0] + 1));
- return TRUE;
- }
- }
- }
-
- /* Can't find it in universal, so let's look in program-specific for Hypercard. */
- kr = qb->quic.application;
- end = kr + N_QCKEYS;
-
- for (; kr < end; kr++) {
- if (kr->QKtype == QK_TEXT) {
- if ((kr->key) == kcode && (kr->modifiers == modifiers)) {
- BlockMove(theText, kr->u.QuicText.text, (Size)(theText[0] + 1));
- return TRUE;
- }
- }
- }
- return FALSE;
- }
-